/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package graphstuff;

import com.mxgraph.swing.mxGraphComponent;
import com.mxgraph.view.mxGraph;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import javax.swing.JFrame;
import kindatamanip.DipOrg;
import kindatamanip.GenerateData;
import kindatamanip.Heuristics;
import kindatamanip.Measurements;

/**
 *
 * @author thbrandston
 */

public class Main extends JFrame implements KeyListener
{

    private mxGraph graph;
    private mxGraphComponent graphComponent;
    private Object parent;
    private int weightCut;
    private DipOrg[] parents;
    private DipOrg[] children;
    private int nParents;
    private int nChildren;
    private int variation;
    private int nLoci;
//    private Label pLabel;
//    private Label cLabel;
//    private Label vLabel;
//    private Label gLabel;

    public void keyPressed(KeyEvent e)
    {

        if(KeyEvent.getKeyText(e.getKeyCode()).equals("R"))
        {
            generate();
            System.out.println("refreshing data...");
        }
        else if(KeyEvent.getKeyText(e.getKeyCode()).equals("G"))
        {
            if((e.getModifiersEx() & KeyEvent.SHIFT_DOWN_MASK) == KeyEvent.SHIFT_DOWN_MASK)
                clearAll();
            showWeightGroups();
            System.out.println("show weightgroups...");
        }
        else if(KeyEvent.getKeyText(e.getKeyCode()).equals("S"))
        {
            if((e.getModifiersEx() & KeyEvent.SHIFT_DOWN_MASK) == KeyEvent.SHIFT_DOWN_MASK)
                clearAll();
            showLinks();
            System.out.println("show sibgroups...");
        }
        else if(KeyEvent.getKeyText(e.getKeyCode()).equals("H"))
        {
            Heuristics.percentBased(80, children, 0);
            System.out.println("use Heuristic...");
        }
        else if(KeyEvent.getKeyText(e.getKeyCode()).equals("W"))
        {
            if((e.getModifiersEx() & KeyEvent.SHIFT_DOWN_MASK) == KeyEvent.SHIFT_DOWN_MASK)
            {
                weightCut = Math.min(weightCut+1, nLoci*2+1);
            }
            else
            {
                weightCut = Math.max(weightCut-1, 0);
            }
            System.out.println("weightCut " + weightCut);
        }
        else if(KeyEvent.getKeyText(e.getKeyCode()).equals("P"))
        {
            if((e.getModifiersEx() & KeyEvent.SHIFT_DOWN_MASK) == KeyEvent.SHIFT_DOWN_MASK)
            {
                nParents++;
            }
            else
            {
                nParents--;
            }
            System.out.println("nParents " + nParents);
        }
        else if(KeyEvent.getKeyText(e.getKeyCode()).equals("C"))
        {
            if((e.getModifiersEx() & KeyEvent.SHIFT_DOWN_MASK) == KeyEvent.SHIFT_DOWN_MASK)
            {
                nChildren++;
            }
            else
            {
                nChildren--;
            }
            System.out.println("nChildren " + nChildren);
        }
        else if(KeyEvent.getKeyText(e.getKeyCode()).equals("V"))
        {
            if((e.getModifiersEx() & KeyEvent.SHIFT_DOWN_MASK) == KeyEvent.SHIFT_DOWN_MASK)
            {
                variation++;
            }
            else
            {
                variation = Math.max(variation-1, 2);
            }
            System.out.println("variation " + variation);
        }
        else if(KeyEvent.getKeyText(e.getKeyCode()).equals("L"))
        {
            if((e.getModifiersEx() & KeyEvent.SHIFT_DOWN_MASK) == KeyEvent.SHIFT_DOWN_MASK)
            {
                nLoci++;
            }
            else
            {
                nLoci = Math.max(nLoci-1, 1);
            }
            System.out.println("nLoci " + nLoci);
        }

    }

    public void keyReleased(KeyEvent e)
    {
        //System.out.println("released " + KeyEvent.getKeyText(e.getKeyCode()));
        //throw new UnsupportedOperationException("Not supported yet.");
    }

    public void keyTyped(KeyEvent e)
    {
        //System.out.println("typed " + KeyEvent.getKeyText(e.getKeyCode()));
        //throw new UnsupportedOperationException("Not supported yet.");
    }
    
    public Main()
    {
        weightCut = 0;

        graph = new mxGraph();
        parent = graph.getDefaultParent();

        nParents = 3;
        nChildren = 9;
        variation = 5;
        nLoci = 10;
//
//        pLabel = new Label();
//        pLabel.setText("#parents " + nParents);
//        pLabel.setLocation(30, 30);
//        getContentPane().add(pLabel);
        
        graphComponent = new mxGraphComponent(graph);
        getContentPane().add(graphComponent);

        //getContentPane().validate();

    }

    private void init()
    {
        graphComponent.addKeyListener(this);
        getContentPane().addKeyListener(this);
        generate();
    }

    private void generate()
    {
        parents = new DipOrg[nParents];
        children = new DipOrg[nChildren];

        GenerateData.generatePandC(parents, children, GenerateData.generatePopulationGenome(nLoci, variation));

    }

    private void clearEdges()
    {
        graph.getModel().beginUpdate();

        try
        {
            graph.selectEdges();
            graph.removeCells(graph.getSelectionCells());
        }
        finally
        {
            graph.getModel().endUpdate();
        }
    }

    private void clearAll()
    {
        graph.getModel().beginUpdate();

        try
        {
            graph.selectAll();
            graph.removeCells(graph.getSelectionCells());
        }
        finally
        {
            graph.getModel().endUpdate();
        }
    }
    
    private void showLinks()
    {

        Object[] pObj = new Object[nParents];
        Object[] cObj = new Object[nChildren];
        
        graph.getModel().beginUpdate();
        
        try
        {

            //create nodes for parents and children
            for(int i = 0; i < nParents; i++)
            {
                pObj[i] = graph.insertVertex(parent, null, "parent" + i,
                        Math.cos(Math.PI/nParents*2*i)*325+400,
                        Math.sin(Math.PI/nParents*2*i)*325+400, 40, 20);
            }
            for(int i = 0; i < nChildren; i++)
            {
                cObj[i] = graph.insertVertex(parent, null, "child" + i,
                        Math.cos(Math.PI/nChildren*2*i)*150+400,
                        Math.sin(Math.PI/nChildren*2*i)*150+400, 40, 20);
            }

            //link parents and children
            for(int i = 0; i < nChildren; i++)
            {
                for(int j = 0; j < nParents; j++)
                {
                    if(children[i].hasParent(parents[j]))
                    {
                        graph.insertEdge(parent, null, "parent", pObj[j], cObj[i]);
                    }
                }
            }
            
            //link children to each other
            for(int i = 0; i < nChildren-1; i++)
            {
                for(int j = i+1; j < nChildren; j++)
                {
                    int w = Measurements.compareAlleles(children[i], children[j]);
                    //System.out.println(w);
                    if(w > weightCut)
                    {
                        graph.insertEdge(parent, null, w, cObj[i], cObj[j]);
                    }
                }
            }
        }
        finally
        {
            graph.getModel().endUpdate();
        }
    }

    private void showWeightGroups()
    {
        Object[] pObj = new Object[nParents];
        Object[] sObj;

        graph.getModel().beginUpdate();
        
        try
        {
            
            // create each parent's node
            for(int i = 0; i < nParents; i++)
            {
                pObj[i] = graph.insertVertex(parent, null, "parent" + i,
                        Math.cos((Math.PI/nParents)*2*i)*325+400,
                        Math.sin((Math.PI/nParents)*2*i)*325+400, 40, 20);
            }

            // for each child, add it to a list under a pair of parents
            ArrayList<ArrayList<DipOrg>> sibLists = new ArrayList(0);

            for(int i = 0; i < nParents-1; i++)
            {
                for(int j = i+1; j < nParents; j++)
                {
                    ArrayList<DipOrg> tmpList = new ArrayList(0);

                    for(int k = 0; k < nChildren; k++)
                    {
                        if(children[k].hasParent(parents[i]) &&
                                children[k].hasParent(parents[j]))
                        {
                            tmpList.add(children[k]);
                        }
                    }
                    sibLists.add(tmpList);
                }
            }

            sObj = new Object[sibLists.size()];

            // go through each sibling list and compare all children in it to each other
            for(int i = 0; i < sibLists.size(); i++)
            {
                int weight = Measurements.avgSharedAlleles(sibLists.get(i));
                if(weight != -1)
                {
                    sObj[i] = graph.insertVertex(parent, null, weight,
                            Math.cos(Math.PI/sibLists.size()*2*i)*275+400,
                            Math.sin(Math.PI/sibLists.size()*2*i)*275+400, 40, 20);
                }
            }

            // go through each sibling list and compare all children in it to all children in each other siblist
            for(int i = 0; i < sibLists.size()-1; i++)
            {
                for(int j = i+1; j < sibLists.size(); j++)
                {
                    int weight = Measurements.avgSharedAlleles(sibLists.get(i), sibLists.get(j));
                    if(weight != -1)
                    {
                        graph.insertEdge(parent, null, weight, sObj[i], sObj[j]);
                    }
                }
            }

        }
        finally
        {
            graph.getModel().endUpdate();
        }
        
    }

    public void showSibListsAt(ArrayList<ArrayList<DipOrg>> sibLists, int x, int y)
    {
        graph.getModel().beginUpdate();

        try
        {

        }
        finally
        {
            graph.getModel().endUpdate();
        }
    }

    public static void main(String[] args)
    {
        Main frame = new Main();
        frame.init();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(800, 800);
        frame.setVisible(true);
    }
}


/*
public class Main extends PApplet implements mxICanvas
{
    private mxGraph graph;
    private int weightCut;
    private DipOrg[] parents;
    private DipOrg[] children;
    private Object[] pObj;
    private Object[] cObj;

    public Object drawCell(mxCellState state)
    {
        //throw new UnsupportedOperationException("Not supported yet.");
        return state.getCell();
    }

    public Object drawLabel(String text, mxCellState state, boolean html)
    {
        //throw new UnsupportedOperationException("Not supported yet.");
        return state.getLabel();
    }

    public double getScale()
    {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    public Point getTranslate()
    {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    public void setScale(double scale)
    {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    public void setTranslate(int x, int y)
    {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    public void setup() {
        // original setup code here ...
        size(400, 400);

        // prevent thread from starving everything else
        noLoop();
    }

    public void draw() {
        graph.drawGraph(this);
    }

    public void mousePressed() {
        // do something based on mouse movement

        // update the screen (run draw once)
        redraw();
    }

    public void keyTyped()
    {
        if(key == '+')
            weightCut++;
        else if(key == '-')
            weightCut--;
    }

    public Main()
    {
        weightCut = 0;

        graph = new mxGraph();
        Object parent = graph.getDefaultParent();

        parents = new DipOrg[3];
        children = new DipOrg[9];
        int[] variation = {9, 8, 5, 6, 9, 3, 4, 7, 8, 4};

        GenerateData.generatePandC(parents, children, GenerateData.generatePopulationGenome(variation.length, variation));

        pObj = new Object[nParents];
        cObj = new Object[nChildren];
        
        graph.getModel().beginUpdate();
        try
        {
            //create nodes for parents and children
            for(int i = 0; i < nParents; i++)
            {
                pObj[i] = graph.insertVertex(parent, null, "parent" + i, i*200+10, 20, 40, 20);
            }
            for(int i = 0; i < nChildren; i++)
            {
                cObj[i] = graph.insertVertex(parent, null, "child" + i,
                        (i%9)*100+10, (i/9)*90+100, 40, 20);
            }

            //link parents and children
            for(int i = 0; i < nChildren; i++)
            {
                for(int j = 0; j < nParents; j++)
                {
                    if(children[i].hasParent(parents[j]))
                    {
                        graph.insertEdge(parent, null, "parent", pObj[j], cObj[i]);
                    }
                }
            }

            //link children to each other
            for(int i = 0; i < nChildren-1; i++)
            {
                for(int j = i+1; j < nChildren; j++)
                {
                    int w = children[i].compareAlleles(children[j]);
                    //System.out.println(w);
                    if(w > weightCut)
                    {
                        graph.insertEdge(parent, null, w, cObj[i], cObj[j]);
                    }
                }
            }

//            DipOrg do1 = new DipOrg(variation.length);
//            Object v1 = graph.insertVertex(parent, null, do1, 20, 20, 80, 30);
//            Object v2 = graph.insertVertex(parent, null, "World!", 240, 150, 80, 30);
//            graph.insertEdge(parent, null, "Edge", v1, v2);
        }
        finally
        {
            graph.getModel().endUpdate();
        }

    }

    public static void main(String[] args)
    {
//        Main papp = new Main();
//        papp.setSize(400, 400);
//        papp.setVisible(true);
//        papp.init();
//        papp.setup();

        Test papp = new Test();
    }


}
*/